#!/usr/bin/python -tt

import re
import sys
import string

#####################################
# todo:
# need to look at the routing table to find the destination zone for asa -> junos policy conversion

#######################################
#   classes:
#      firewall_config
#         contains all things that would need to be changed in a firewall: object groups, access-lists (with ACEs), statics, and routes
#         contructors:
#            empty config
#            pass a filename and have it read in the config, returning conf object instance
#      objectgroup
#         has a type
#         has a list of network-objects and service-objects
#             there should be expanded and symbolic versions of these
#      access-list list of ACEs
#      ACE access list entry, perhaps include line number
#      static
#      route

class FirewallConfig:
   
   def __init__(self, filename):
      
      self.verbose_mode = True
      #self.verbose_mode = False
      
      self.filename = filename
      file = open(filename)
      
      # suck entire file into config_text attribute
      self.config_text = file.read()
      file.seek(0)
      # read every line in the file as well
      self.config_lines = file.readlines()
      # close file at earliest moment
      file.close()
      
      # strip newline at end of each line
      #self.vprint("stripping line endings off of config_lines list")
      last_index = len(self.config_lines) - 1
      i = 0
      while (i <= last_index):
         #self.vprint("line before >" + self.config_lines[i] + "<")
         self.config_lines[i] = self.config_lines[i].rstrip()
         #self.vprint("line after >" + self.config_lines[i] + "<")
         i = i + 1
      
      #######################
      # global properties of firewall
      self.vendor =             ""
      self.type =               ""
      self.subtype =            ""
      self.name =               ""
      self.fw_version_line =    None
      
      #######################
      # dictionaries and lists used to store fields of class
      self.names_list        = []
      self.names_dict        = {}
      self.og_dict           = {}
      self.access_group_dict = {}
      self.access_list_dict  = {}
      self.static_list       = []
      self.route_list        = []

      # go thru lines in fw, until one shows the fw type version etc
      firewall_version_line_regex = r"^\s*((PIX|FWSM|ASA) [Vv]ersion \d|set zone )"
      for line in self.config_lines:
         #line = line.rstrip()
         #self.vprint("looking at line: >" + line + "<")
         match = re.match(firewall_version_line_regex, line)
         if match:
            self.fw_version_line = line
            self.vprint("fw version line: " + self.fw_version_line)
            break
      if self.fw_version_line is None:
         print "Error: empty config or invalid/unrecognized firewall config file"
         exit()

      
      # use this found version line in tests below
      # find vendor first; search patterns below will depend on this
      if re.match(r"(PIX|FWSM|ASA)", self.fw_version_line):
         self.vendor = "Cisco"
      if re.match(r"set zone", self.fw_version_line):
         self.vendor = "Juniper"
      self.vprint("found fw vendor: " + self.vendor)
      
      # example Cisco FW version lines:
      #PIX Version 6.3(3)
      #FWSM Version 4.0(5) <context>
      #ASA Version 8.0(4)
      
      # using fw_version_line, find type etc
      # designate appropriate search string, based on vendor
      firewall_type_regex = ""
      if self.vendor == "Cisco":
         firewall_type_regex = r"^(PIX|FWSM|ASA) [Vv]ersion (\S+)"
      elif self.vendor == "Juniper":
         # can't determine type on Juniper, assume SSG
         firewall_type_regex = "SSG"
      # if possible, find type and version
      if firewall_type_regex != "":
         match = re.match(firewall_type_regex, self.fw_version_line)
         if match:
            self.type = match.group(1)
            self.subtype = match.group(2)
            self.vprint("found fw type : " + self.type + " and subtype: " + self.subtype)
   
      # armed with knowledge of firewall vendor, find name
      firewall_name_regex = ""
      if self.vendor == "Cisco":
         firewall_name_regex = r"^\s*hostname (\S+)"
      elif self.vendor == "Juniper":
         firewall_name_regex = r"^\s*set hostname (\S+)"
      # loop through, finding magic hostname line, and snatch it
      if firewall_name_regex != "":
         for line in self.config_lines:
            #line = line.rstrip()
            match = re.match(firewall_name_regex, line)
            if match:
               self.name = match.group(1)
               self.vprint("found fw name: " + self.name + " in line: " + line )
               break
   
      
      # parse config for names
      # example: name 206.9.48.38 CORRAL_NET_2
      self.vprint("finding names")
      address = ""
      label   = ""
      for line in self.config_lines:
         #self.vprint("looking at line: >" + line + "<")
         match = re.search(r'^name (.+) (.+)$', line)
         if match:
            address = match.group(1)
            label   = match.group(2)
            self.vprint("name found " + label + " = " + address + "")
            self.names_list.append(Name(address, label))
            self.names_dict[label] = address
      self.vprint("done finding names")
      
      # parse config for object-groups
      # the ugly line by line method; multiline regular expression method was sucky
      self.vprint("finding object groups")
      last_index = len(self.config_lines) - 1
      i = 0
      while (i <= last_index):
         line = self.config_lines[i]
         #self.vprint("i'm working on: >" + line + "<")
         object_group_prologue_regex = r"^\s*object-group (\S+) (\S+)\b"
         match = re.match(object_group_prologue_regex, line)
         if match:
            # we are in an object group section
            type = match.group(1)
            name = match.group(2)
            # if there is a tcp-udp option, glom onto it
            object_group_prologue_tcpudp_regex = r"^\s*object-group \S+ \S+ (tcp-udp|tcp|udp)\b"
            match = re.match(object_group_prologue_tcpudp_regex, line)
            if match:
               # we are in an object group section
               tcp_udp_option = match.group(1)
            else:
               tcp_udp_option = ""
            #self.vprint("detected object group prologue, type: " + type + " name: " + name)
            # go to next line, which could be description, OG item, another non-OG line in config, or EOF
            i = i + 1
            
            # find description, if any
            line = self.config_lines[i]
            object_group_desc_regex = r"^\s*description (.*)$"
            match = re.match(object_group_desc_regex, line)
            if match:
               description = match.group(1)
               #self.vprint("matched description: " + description)
               # get off the description line
               i = i + 1
            else:
               #self.vprint("didn't match description")
               description = ""
            
            # create item list which we'll send to the OG constructor
            cur_og_item_list = [ ]
            # at this point, we are on a line after the OG prologue and possible description
            object_group_item_regex = r"^\s*((?:network|port|protocol|icmp|group)-object .*)$"
            while (re.match(object_group_item_regex, self.config_lines[i])):
               match = re.match(object_group_item_regex, self.config_lines[i])
               item_str = match.group(1)
               new_item = ObjectGroupItem(item_str)
               cur_og_item_list.append(new_item)
               #self.vprint("detected object group item: " + item)
               # go to next line
               i = i + 1
            # send collected item list to the OG constructor
            og = ObjectGroup(name, type, tcp_udp_option, description, cur_og_item_list)
            # add newly formed OG to our list of OGs in the FirewallConfig object
            if og:
               #self.og_dict.append(og) (pre dictionary version)
               self.add_objectgroup(og)
            # end of object group match
         else:
            # if the line wasn't an OG prologue, go to next line
            i = i + 1
         # end of while loop block
      self.vprint("done finding object groups")
      
      # parse config for access-groups
      # example access group: access-group acl-vend in interface vendor
      self.vprint("finding access-groups")
      #access_group_line = ""
      #access_group_acl = ""
      for line in self.config_lines:
         match = re.search(r'^access-group (\S+) in interface \S+$', line)
         if match:
            access_group_line = match.group(0)
            access_group_acl = match.group(1)
            self.vprint("access-group found: >" + access_group_line + "< with referenced acl: >" + access_group_acl + "<")
            self.access_group_dict[access_group_acl] = access_group_line
      self.vprint("done finding access-groups")
      
      # parse config for access-lists
      self.vprint("finding access-lists")
      #access_list_line = ""
      #access_list_name = ""
      for line in self.config_lines:
         match = re.search(r'^(access-list (\S+) .*)$', line)
         if match:
            access_list_line = match.group(1)
            access_list_name = match.group(2)
            #self.vprint("access-list found, name: " + access_list_name)
            # first check to see if this acl line has an access-group associated with it; if not, skip
            if not self.access_group_dict.has_key(access_list_name):
               continue
            # if we didn't go to next line, this access-list must be important
            if self.access_list_dict.has_key(access_list_name):
               # if we find the access-list with that name, add this line to it
               self.vprint("storing access-list line in access-list: " + access_list_name)
               self.access_list_dict[access_list_name].add_acl_line(access_list_line)
            else:
               # create new access_list object, with first line to be added to the list
               self.vprint("creating new access-list: " + access_list_name)
               new_access_list = AccessList(access_list_name, access_list_line)
               self.access_list_dict[access_list_name] = new_access_list
      self.vprint("done finding access-lists")
      
      # parse config for statics
      self.vprint("finding statics")
      static_nat = ""
      for line in self.config_lines:
         match = re.search(r'^(static .*)$', line)
         if match:
            static_nat = match.group(1)
            #self.vprint("static found: >" + static_nat + "<")
            self.static_list.append(StaticNAT(static_nat))
      self.vprint("done finding statics")
      
      # parse config for routes
      #self.vprint("finding routes")
      route = ""
      for line in self.config_lines:
         match = re.search(r'^(route .*)$', line)
         if match:
            route = match.group(1)
            #self.vprint("route found: >" + route + "<")
            self.route_list.append(Route(route))
      #self.vprint("done finding routes")
  
   def convert_application_to_junos(self, orig_app):
      junos_app = orig_app
      match = re.search("^[ ]*(\d+) (\d+)[ ]*$", orig_app)
      if match:
         port_1   = match.group(1)
         port_2   = match.group(2)
         junos_app = "%s-%s" % (port_1, port_2)
      return junos_app

   def convert_address_to_junos(self, orig_address):
      #print "DEBUG: adding orig_address = %s" % (orig_address)
      junos_address = orig_address
      match = re.search("^[ ]*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[ ]*$)", orig_address)
      if match:
         host_portion   = match.group(1)
         slash_netmask  = "/32"
         junos_address = "%s%s" % (host_portion, slash_netmask)
      match = re.search("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", orig_address)
      if match:
         # this entry has a network mask to deal with
         host_portion   = match.group(1)
         cidr_netmask   = match.group(2)
         print "DEBUG: convert_address_to_junos >%s< >%s<" % (host_portion, cidr_netmask)
         slash_netmask  = self.mask_cidr_to_slash(cidr_netmask)
         junos_address = "%s%s" % (host_portion, slash_netmask)
      return junos_address

   def mask_cidr_to_slash(self, cidr_mask):
      print "DEBUG: mask_cidr_to_slash: finding match >%s<" % (cidr_mask)
      regex_sub_dict = {
         "255.255.255.255"  :    "/32" ,
         "255.255.255.254"  :    "/31" ,
         "255.255.255.252"  :    "/30" ,
         "255.255.255.248"  :    "/29" ,
         "255.255.255.240"  :    "/28" ,
         "255.255.255.224"  :    "/27" ,
         "255.255.255.192"  :    "/26" ,
         "255.255.255.128"  :    "/25" ,
         "255.255.255.0"    :    "/24" ,
         "255.255.254.0"    :    "/23" ,
         "255.255.252.0"    :    "/22" ,
         "255.255.248.0"    :    "/21" ,
         "255.255.240.0"    :    "/20" ,
         "255.255.224.0"    :    "/19" ,
         "255.255.192.0"    :    "/18" ,
         "255.255.128.0"    :    "/17" ,
         "255.255.0.0"      :    "/16" ,
         "255.254.0.0"      :    "/15" ,
         "255.252.0.0"      :    "/14" ,
         "255.248.0.0"      :    "/13" ,
         "255.240.0.0"      :    "/12" ,
         "255.224.0.0"      :    "/11" ,
         "255.192.0.0"      :    "/10" ,
         "255.128.0.0"      :    "/9"  ,
         "255.0.0.0"        :    "/8"  ,
         "254.0.0.0"        :    "/7"  ,
         "252.0.0.0"        :    "/6"  ,
         "248.0.0.0"        :    "/5"  ,
         "240.0.0.0"        :    "/4"  ,
         "224.0.0.0"        :    "/3"  ,
         "192.0.0.0"        :    "/2"  ,
         "128.0.0.0"        :    "/1"  ,
         "0.0.0.0"          :    "/0"  }
      replacement = regex_sub_dict[cidr_mask]
      print "DEBUG: mask_cidr_to_slash: found match: >%s<" % (replacement)
      return replacement

   def get_objectgroup(self, og_name):
      if og_name in self.og_dict:
         return self.og_dict[og_name]
      else:
         return None
   
   def add_objectgroup(self, og):
      og_name = og.name
      if not self.og_dict.has_key(og_name):
         self.og_dict[og_name] = og
      else:
         print "Error: in add_objectgroup of FirewallConfig class, attempted to add duplicate OG name (" + og_name + ") to dict of OGs"
   
   def print_me(self):
      # print the data structure, not to be used for config snippets
      print "#### Firewall vendor: " + self.vendor
      print "#### Firewall type: " + self.type + " " + self.subtype
      print "#### Firewall name: " + self.name
      
      print "#### OGs: "
      for name in self.og_dict.keys():
         self.og_dict[name].print_me()
      print "#### ACLs: "
      for acl_name in self.access_list_dict.keys():
         self.access_list_dict[acl_name].print_me()
      print "#### Access groups: "
      for acl_name in self.access_group_dict.keys():
         self.access_group_dict[acl_name].print_me()
      print "#### Statics: "
      for static_nat in self.static_list:
         static_nat.print_me()
      print "#### Routes: "
      for route in self.route_list:
         route.print_me()

#   def resolve_object_groups_in_acls(self):
#      for acl_name in self.access_list_dict.keys():
#         num_acl_lines = len(self.access_list_dict[acl_name].acl_line_list)
#         last_acl_line_index = num_acl_lines - 1
#         cur_acl_line_index = 0
#         while (cur_acl_line_index <= last_acl_line_index): 
#            self.access_list_dict[acl_name].make_og_substitution()

   def resolve_port_names_in_object_groups(self):
      for og_name in self.og_dict.keys():
         for name in self.names_list:
            if self.og_dict[og_name].type == "service":
               self.og_dict[og_name].make_port_substitution()

   def resolve_names_and_object_groups(self):
      for og_name in self.og_dict.keys():
         for name in self.names_list:
            if self.og_dict[og_name].contains_name(name):
               self.og_dict[og_name].make_name_substitution(name)
      for og_name in self.og_dict.keys():
         if self.og_dict[og_name].has_nested_object_group():
            self.og_dict[og_name].make_object_group_substitutions(self)
      for og_name in self.og_dict.keys():
         if self.og_dict[og_name].has_32_bit_item():
            self.og_dict[og_name].simplify_32_bit_items()
   
   def vprint(self, line):
      # verbose print, if in verbose mode
      if self.verbose_mode:
         print line

class ObjectGroup:
   
   def __init__(self, name, type, tcp_udp_option, description, og_item_list):
      #print "begin ObjectGroup constructor"
      self.name =           name
      self.type =           type
      self.tcp_udp_option = tcp_udp_option
      self.description =    description
      self.item_list =      og_item_list
      #print "end ObjectGroup constructor"
   
   def __str__(self):
      str_representation = ""
      if self.tcp_udp_option == "":
         str_representation += "object-group " + self.type + " " + self.name + "\n"
      else:
         str_representation += "object-group " + self.type + " " + self.name + " " + self.tcp_udp_option + "\n"
      
      if self.description != "":
         str_representation += "description " + self.description + "\n"
      for item in self.item_list:
         str_representation += " " + item.item + "\n"
      return str_representation
   
   def print_me(self):
      # print the data structure, not to be used for config snippets
      print "ObjectGroup name: " + self.name + " type: " + self.type,
      if self.tcp_udp_option != "":
         print " tcp_udp_option: " + self.tcp_udp_option,
      if self.description != "":
         print " description: " + self.description,
      print ""
      print "items: "
      for item in self.item_list:
         print item
   
   def print_config_format(self):
      # print OG in the Cisco config format for config snippets
      
      # example objectgroup
      #object-group network ng-outside-placeware_servers
      # description IP's of placeware servers used for MS Live Meeting
      # network-object 204.176.46.0 255.255.255.0
      # network-object 64.69.171.0 255.255.255.0
      print_output = self.__str__()
      print print_output
         
   def add_item(self, item):
      # add an item
      self.item_list.append(item)
   
   def remove_item(self, item):
      # if it's there, remove it
      if self.item_list.count(item) > 0:
         self.item_list.remove(item)
   
   def contains_IP(self, IP):
      for item in self.item_list:
         if item.contains_IP(IP):
            return True
      return False
   
   def get_item_with_IP(self, IP):
      for item in self.item_list:
         if item.contains_IP(IP):
            return item
      # at this point, the for loop didn't match any item, so send back None and print warning
      print "get_item_with_IP() warning: item not in ObjectGroup"
      return None
   
   def clone_IP(self, old_IP, new_IP):
      # clones IP in object group instance
      # note: does not return commands to do so, just changes the internal instance, use get_conf_clone_IP() for this functionality
      if not self.contains_IP(old_IP):
         print >> sys.stderr, "Error in ObjectGroup.clone_IP(): oldIP not present in og: " + old_IP
         return
      new_item = ObjectGroupItem(" network-object host " + new_IP)
      #print "debug: og.clone_IP: new item is:"
      print new_item
      self.item_list.append(new_item)
   
   def has_nested_object_group(self):
      for item in self.item_list:
         if item.contains_re("^\s*group-object "):
            return True
      return False
   
   def has_32_bit_item(self):
      for item in self.item_list:
         if item.contains_re("^\s*network-object .* 255.255.255.255\s*$"):
            return True
      return False

   def simplify_32_bit_items(self):
      for item in self.item_list:
         if item.contains_re("^\s*network-object .* 255.255.255.255\s*$"):
            new_item = re.sub(r"^\s*network-object (.*) 255\.255\.255\.255\s*$", r" network-object host \1", item.item)
            item.item = new_item 

   def make_port_substitution(self):
      # replace items in OG with port-object range 123 123 and port-object eq https
      # Name Port
      port_name_number_dict = { "bgp"            :     "179",
         "biff"           :     "512",
         "bootpc"         :     "68",
         "bootps"         :     "67",
         "chargen"        :     "19",
         "citrix-ica"     :     "1494",
         "cmd"            :     "514",
         "daytime"        :     "13",
         "discard"        :     "9",
         "dnsix"          :     "195",
         "domain"         :     "53",
         "echo"           :     "7",
         "exec"           :     "512",
         "finger"         :     "79",
         "ftp"            :     "21",
         "ftp-data"       :     "20",
         "gopher"         :     "70",
         "h323"           :     "1720",
         "http"           :     "80",
         "https"          :     "443",
         "hostname"       :     "101",
         "ident"          :     "113",
         "irc"            :     "194",
         "isakmp"         :     "500",
         "klogin"         :     "543",
         "kshell"         :     "544",
         "login"          :     "513",
         "lpd"            :     "515",
         "mobile-ip"      :     "434",
         "nameserver"     :     "42",
         "netbios-dgm"    :     "138",
         "lpd"            :     "515",
         "mobile-ip"      :     "434",
         "nameserver"     :     "42",
         "netbios-dgm"    :     "138",
         "netbios-ns"     :     "137",
         "nntp"           :     "119",
         "ntp"            :     "123",
         "pim-auto-rp"    :     "496",
         "pop2"           :     "109",
         "pop3"           :     "110",
         "radius"         :     "1645",
         "radius-acct"    :     "1646",
         "rip"            :     "520",
         "smtp"           :     "25",
         "snmp"           :     "161",
         "snmptrap"       :     "162",
         "sqlnet"         :     "1521",
         "ssh"            :     "22",
         "sunrpc"         :     "111",
         "syslog"         :     "514",
         "tacacs"         :     "49",
         "talk"           :     "517",
         "telnet"         :     "23",
         "tftp"           :     "69",
         "time"           :     "37",
         "uucp"           :     "540",
         "who"            :     "513",
         "whois"          :     "43",
         "www"            :     "80",
         "xdmcp"          :     "177" }

      for item in self.item_list:
         port_number = "not defined"
         # handle port-object eq ntp
         if item.contains_re(r"^\s*port-object eq [A-z][-A-z0-9]*"):
            pattern = r"^\s*port-object eq ([A-z][-A-z0-9]*)\s*$"
            match = re.search(pattern, item.item)
            if match:
               port_name = match.group(1)
            else:
               print "ObjectGroup.make_port_substitution() error: found word instead of number for port, but couldn't extract that word; item = >" + item.item + "<"
               continue
            if port_name in port_name_number_dict:
               port_number = port_name_number_dict[port_name]
               #print "found port number: " + port_number
            else:
               print "ObjectGroup.make_port_substitutions() warning: no key in port name number dict found for >" + port_name + "<"
               continue
            item.item = item.item.replace(port_name, port_number)
         # handle port-object range ntp 124
         elif item.contains_re(r"^\s*port-object range [A-z][-A-z0-9]* [0-9]+\b"):
            pattern = r"^\s*port-object range ([A-z][-A-z0-9]*) "
            match = re.search(pattern, item.item)
            if match:
               port_name = match.group(1)
            else:
               print "ObjectGroup.make_port_substitution() error: found word instead of number for port, but couldn't extract that word; item = >" + item.item + "<"
               continue
            if port_name in port_name_number_dict:
               port_number = port_name_number_dict[port_name]
               #print "found port number: " + port_number
            else:
               print "ObjectGroup.make_port_substitutions() warning: no key in port name number dict found for >" + port_name + "<"
               continue
            item.item = re.sub(pattern, " port-object range " + port_number + " ", item.item)
         # handle port-object range 122 ntp
         elif item.contains_re(r"^\s*port-object range [0-9]+ [A-z][-A-z0-9]*\b"):
            pattern = r"^\s*port-object range ([0-9]+) ([A-z][-A-z0-9]*)\b"
            match = re.search(pattern, item.item)
            if match:
               port_name = match.group(2)
            else:
               print "ObjectGroup.make_port_substitution() error: found word instead of number for port, but couldn't extract that word; item = >" + item.item + "<"
               continue
            if port_name in port_name_number_dict:
               port_number = port_name_number_dict[port_name]
               #print "found port number: " + port_number
            else:
               print "ObjectGroup.make_port_substitutions() warning: no key in port name number dict found for >" + port_name + "<"
               continue
            item.item = re.sub(pattern, " port-object range \1 " + port_number, item.item)
         # handle port-object range ntp radius
         elif item.contains_re(r"^\s*port-object range [A-z][-A-z0-9]* [A-z][-A-z0-9]*\b"):
            pattern = r"^\s*port-object range ([A-z][-A-z0-9]*) ([A-z][-A-z0-9]*)\b"
            match = re.search(pattern, item.item)
            if match:
               port_name_1 = match.group(1)
               port_name_2 = match.group(2)
            else:
               print "ObjectGroup.make_port_substitution() error: found word instead of number for port, but couldn't extract that word; item = >" + item.item + "<"
               continue
            if ((port_name_1 in port_name_number_dict) and (port_name_2 in port_name_number_dict)):
               port_number_1 = port_name_number_dict[port_name_1]
               port_number_2 = port_name_number_dict[port_name_2]
               #print "found port numbers: " + port_number_1 + " " + port_number_2
            else:
               print "ObjectGroup.make_port_substitutions() warning: no key in port name number dict found for >" + port_name_1 + " " + port_name_2 + "<"
               continue
            item.item = re.sub(pattern, " port-object range " + port_number_1 + " " + port_number_2, item.item)
         if item.contains_re(r"^\s*port-object range (\S+) \1\b"):
            item.item = re.sub(r"^\s*port-object range (\S+) \1\b", r" port-object eq \1", item.item)
            

   def make_object_group_substitutions(self, parent_fwconfig):
      num_passes = 0
      max_passes = 20
      while True:
         num_passes = num_passes + 1
         if num_passes > max_passes:
            break
         # quit from infinite loop if we find there are no more nested groups in this og
         if not self.has_nested_object_group():
            break
         # search and destroy: go through multiple passes, replacing each group-object item with the referred to OG's item(s)
         for item in self.item_list:
            if item.contains_re(r"^\s*group-object "):
               pattern = r"^\s*group-object (.+)$"
               match = re.search(pattern, item.item)
               # get og name
               if match:
                  referenced_object_group_name = match.group(1)
               else:
                  print "ObjectGroup.make_object_group_substitutions() error: found group-object signature in for loop, but no object-group found to be referenced!"
                  return None
               # check if name is present in fwconfig (it should be!)
               if referenced_object_group_name in parent_fwconfig.og_dict:
                  referenced_object_group = parent_fwconfig.og_dict[referenced_object_group_name]
               else:
                  print "ObjectGroup.make_object_group_substitutions() error: found group-object signature, but object-group referenced doesn't match any OG in current fwconf!"
                  return None
               # for each item in the OG that was referred to by this item, add it
               for new_item in referenced_object_group.item_list:
                  self.add_item(new_item)
               # remove this item (now that we've added each item of the ref'd OG to this OG)
               self.remove_item(item)
      
   def replace_IP(self, old_IP, new_IP):
      # replaces IP in object group instance
      # note: does not return commands to do so, just changes the internal instance, use get_conf_replace_IP() for this functionality
      for item in self.item_list:
         if item.contains_IP(old_IP):
            item.replace_IP(old_IP, new_IP)
   
   def get_conf_replace_IP(self, mode, old_IP, new_IP):
      # returns set of CiscoFirewall config commands to perform a replacement IP
      # mode can be: oneshot or split (not implemented yet)
      if self.tcp_udp_option == "":
         og_prologue = "object-group " + self.type + " " + self.name
      else:
         og_prologue = "object-group " + self.type + " " + self.name + " " + self.tcp_udp_option
      # list of commands always starts off with prologue
      commands = [ og_prologue ]
      for item in self.item_list:
         if item.contains_IP(old_IP):
            old_IP_pattern = r"\b" + re.sub("\.", r"\.", old_IP) + r"\b"
            add_command    = " " + re.sub(old_IP_pattern, new_IP, item)
            remove_command = " no " + item
            commands.append(add_command)
            commands.append(remove_command)
      return commands
   
   def get_conf_clone_IP(self, old_IP, new_IP):
      # returns set of CiscoFirewall config commands to perform a replacement IP
      # mode can be: oneshot or split (not implemented yet)
      if self.tcp_udp_option == "":
         og_prologue = "object-group " + self.type + " " + self.name
      else:
         og_prologue = "object-group " + self.type + " " + self.name + " " + self.tcp_udp_option
      # list of commands always starts off with prologue
      commands = [ og_prologue ]
      for item in self.item_list:
         if item.contains_IP(old_IP):
            old_IP_pattern = r"\b" + re.sub("\.", r"\.", old_IP) + r"\b"
            add_command    = " " + re.sub(old_IP_pattern, new_IP, item.item)
            commands.append(add_command)
      return commands

   def print_item_list(self):
      for item in self.item_list:
         print("OG.print_item_list() item: >" + item.item + "<")

   def contains_name(self, name):
      # convert strings like DDT.NETWORK -> strings like DDT\.NETWORK
      string_pattern = re.sub("\.", r"\.", name.label)
      #string_pattern = r".*\b" + string_pattern + r"\b.*"
      string_pattern = r"\b" + string_pattern + r"\b"
      #print("DEBUG: OG.contains_name() using pattern: >" + string_pattern + "<")
      for item in self.item_list:
         #print("DEBUG: OG.contains_name() checking item: >" + item.item + "<")
         match = re.search(string_pattern, item.item)
         if match:
            #self.vprint("OG.test_if_string_contains_name() true")
            return True
         else:
            pass
            #self.vprint("OG.test_if_string_contains_name() false")
      # if we got to this point without returning true, we never found a match in all the items
      return False

   def make_name_substitution(self, name):
      # convert strings like DDT.NETWORK -> strings like DDT\.NETWORK
      string_pattern = re.sub("\.", r"\.", name.label)
      #string_pattern = r"\b" + string_pattern + r"\b"
      string_pattern = r" " + string_pattern + r" "
      #print("DEBUG: OG.make_name_substitution() using pattern: >" + string_pattern + "<")
      #print("DEBUG: started make_name_substitution() in OG: " + self.name + " w string_pattern: " + string_pattern)
      for item in self.item_list:
         #print("DEBUG: looking at item in OG.item_list: " + item.item + " searching for pattern: " + string_pattern)
         match = re.search(string_pattern, item.item)
         if match:
            #print("DEBUG: (matched in ogi loop)")
            #print("pattern: " + string_pattern + " replaced with: " + name.address + " in the following string: " + ogi.item)
            new_item = re.sub(string_pattern, " " + name.address + " ", item.item)
            #print("item after replacement: " + new_item)
            item.item = new_item
         else:
            pass
            #print("DEBUG: (didn't match in ogi loop)")

class ObjectGroupItem:

   def __init__(self, item):
      self.item = item
      match = re.search("^[ ]*(network-object) host (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      match = re.search("^[ ]*(network-object) (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      match = re.search("^[ ]*(port-object) eq (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      match = re.search("^[ ]*(port-object) range (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      match = re.search("^[ ]*(group-object) (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      match = re.search("^[ ]*(protocol-object) (.+)$", item)
      if match:
         self.right_hand_side = match.group(2)
         return
      self.right_hand_side = "unk rhs"
      print "DEBUG: didn't understand OGI: %s" % (item)
   
   def __str__(self):
      return self.item
   
   def print_config_format(self):
      # print OGI in the Cisco config format for config snippets
      
      # example objectgroup
      #object-group network ng-outside-placeware_servers
      # description IP's of placeware servers used for MS Live Meeting
      # network-object 204.176.46.0 255.255.255.0
      # network-object 64.69.171.0 255.255.255.0
      print " " + self.item
   
   def contains_re(self, re_pattern):
      match = re.search(re_pattern, self.item)
      if match:
         return True
      else:
         return False
   
   def contains_IP(self, IP):
      # convert 192.168.83.19 -> 192\.168\.83\.19
      IP_pattern = re.sub("\.", r"\.", IP)
      #vprint("OGI.contains_IP() using IP: >" + IP_pattern + "<")
      IP_pattern = r"\b" + IP_pattern + r"\b"
      #vprint("OGI.contains_IP() checking item: " + item)
      match = re.search(IP_pattern, self.item)
      if match:
         #vprint("OGI.contains_IP() true")
         return True
      else:
         #vprint("OGI.contains_IP() false")
         return False
   
   def get_IP(self):
      # convert 192.168.83.19 -> 192\.168\.83\.19
      IP_pattern = r"\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b"
      match = re.search(IP_pattern, self.item)
      if match:
         return match.group(1)
      else:
         print "ObjectGroupItem.get_IP() error: no IP found"
         return None
   
   def replace_IP(self, old_IP, new_IP):
      # replaces IP inside this ObjectGroupItem instance
      # (does not return the command to do so, only changes the data structure)
      if self.contains_IP(old_IP):
         old_IP_pattern = r"\b" + re.sub("\.", r"\.", old_IP) + r"\b"
         self.item = re.sub(old_IP_pattern, new_IP, self.item)


class AccessList:
   def __init__(self, acl_name, acl_line):
      self.name = acl_name
      self.acl_line_list = [ acl_line ]
   def contains_og(self):
      for acl_line in self.acl_line_list:
         match = re.search(r' object-group ', acl_line)
         if match:
            return True
      return False
   def make_og_substitution(self):
      while self.contains_og():
         pass
         match = re.search(r' object-group ', "")
         #self.acl_line_list[i] = re.sub()
   def add_acl_line(self, acl_line):
      self.acl_line_list.append(acl_line)
   def print_me(self):
      print "AccessList.print_me() name: " + self.name
      print "acl lines: "
      for acl_line in self.acl_line_list:
         print acl_line
   def convert_to_junos(self, parent_fwconfig):
      policy_number                       = 0
      policy_name                         = ""
      policy_from_to                      = ""
      junos_address_entry_list            = []
      junos_address_set_list              = []
      junos_address_policy_statement_list = []
      for acl_line in self.acl_line_list:
         if re.search("access-list [^ ]+ remark", acl_line):
            print "DEBUG: convert_to_junos - skipping remark acl"
            continue
         if re.search("access-list .* permit ip", acl_line):
            print "DEBUG: convert_to_junos - skipping ip acl"
            continue
         if re.search("access-list .* any ", acl_line):
            print "DEBUG: convert_to_junos - skipping any acl"
            continue
         og_name       = ""
         tcp_protocol  = False
         udp_protocol  = False
         policy_number = policy_number + 1
         protocol_list                  = []
         source_list                    = []
         destination_list               = []
         application_list               = []
         security_policy_list           = []
         acl_line_remaining             = acl_line

         print "### convert_to_junos - converting following line: %s" % (acl_line)
         
         # set policy_from_to field
         # if we recognize the acl direction, set policy_from_to
         if re.search("acl-out", self.name):
            policy_from_to = "from-zone trust to-zone untrust"
            policy_from    = "trust"
            policy_to      = "untrust"
         elif re.search("acl-in", self.name):
            policy_from_to = "from-zone untrust to-zone trust"
            policy_from    = "untrust"
            policy_to      = "trust"
         else:
            # may want to ask user what to call it here
            policy_from_to = "from-zone UNK1 to-zone UNK2"
            policy_from    = "UNK1"
            policy_to      = "UNK2"

         # populate protocol field
         print "DEBUG: populating protocol field - with leftover: %s" % (acl_line_remaining)
         match = re.search("^access-list [^ ]+ (?:extended) (permit|deny) object-group ([^ ]+) (.*)$", acl_line_remaining)
         if match:
            og_name = match.group(2)
            acl_line_remaining = match.group(3)
            print "DEBUG: populating field based on og: %s" % (og_name)
            og = parent_fwconfig.get_objectgroup(og_name)
            # set applications application SG-MOM_MONITOR_PORTS term 1 protocol tcp
            # set applications application SG-MOM_MONITOR_PORTS term 1 destination-port 1270
            # set applications application SG-MOM_MONITOR_PORTS term 2 protocol udp
            # set applications application SG-MOM_MONITOR_PORTS term 2 destination-port 1270
            for protocol in og.item_list:
               #print "DEBUG: adding this to protocol_list: item.right_hand_side = %s" % (protocol.right_hand_side)
               protocol_list.append(protocol.right_hand_side)
               if re.search("[Tt][Cc][Pp]", protocol.right_hand_side):
                  tcp_protocol = True
               elif re.search("[Uu][Dd][Pp]", protocol.right_hand_side):
                  udp_protocol = True
         else:
            print "DEBUG: convert_to_junos - no og in protocol field found"
            match = re.search("^access-list [^ ]+ (?:extended) (permit|deny) ([^ ]+) (.*)$", acl_line_remaining)
            if match:
               protocol_field = match.group(2)
               acl_line_remaining = match.group(3)
               print "DEBUG: populating protocol field: %s" % (protocol_field)
               protocol_list.append(protocol_field)
               if re.search("[Tt][Cc][Pp]", protocol_field):
                  tcp_protocol = True
               elif re.search("[Uu][Dd][Pp]", protocol_field):
                  udp_protocol = True
            else:
               print "DEBUG: error - no protocol or og for protocol found"
         
         # populate source field
         source_address = ""
         print "DEBUG: populating source field - with leftover: %s" % (acl_line_remaining)
         match = re.search("^[ ]*object-group ([^ ]+) (.+)$", acl_line_remaining)
         if match:
            og_name = match.group(1)
            acl_line_remaining = match.group(2)
            print "DEBUG: populating source field based on og: %s" % (og_name)
            og = parent_fwconfig.get_objectgroup(og_name)
            # the source_list in the policy will only consist of the address-set we're about to create
            source_list.append(og_name)
            # set security zones security-zone untrust address-book address 10.156.250.230/32 10.156.250.230/32
            # set security zones security-zone untrust address-book address 10.156.250.15/32 10.156.250.15/32
            # set security zones security-zone untrust address-book address-set NG-OUTSIDE-DMZ_NETWORK address 10.156.250.0/24
            # set security zones security-zone untrust address-book address-set NG-OUTSIDE-DMZ_SWITCHES address 10.156.250.231/32
            for source in og.item_list:
               #print "DEBUG: adding source_address = %s" % (source.right_hand_side)
               source_address = parent_fwconfig.convert_address_to_junos(source.right_hand_side)
               address_entry_statement = "set security zones security-zone %s address-book address %s %s"             % (policy_from, source_address, source_address)
               address_set_statement   = "set security zones security-zone %s address-book address-set %s address %s" % (policy_from, og_name,        source_address)
               junos_address_entry_list.append(address_entry_statement)
               junos_address_set_list.append(address_set_statement)
               print address_entry_statement
               print address_set_statement
         else:
            print "DEBUG: convert_to_junos - no og in source field found"
            match = re.search("^[ ]*host ([^ ]+) (.+)$", acl_line_remaining)
            if match:
               source_field      = match.group(1)
               acl_line_remaining = match.group(2)
               source_address    = "%s%s" % (source_field, "/32")
               print "DEBUG: populating source field: %s" % (source_address)
               source_list.append(source_address)
            else:
               match = re.search("^[ ]*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (.+)$", acl_line_remaining)
               if match:
                  source_field =      match.group(1)
                  acl_line_remaining = match.group(2)
                  source_address = parent_fwconfig.convert_address_to_junos(source_field)
                  print "DEBUG: populating source field: %s" % (source_address)
                  source_list.append(source_address)
               else:
                  print "DEBUG: ERROR didn't match source field!!"
            address_entry_statement = "set security zones security-zone %s address-book address %s %s" % (policy_from, source_address, source_address)
            junos_address_entry_list.append(address_entry_statement)
            print address_entry_statement
         
         # populate destination field
         print "DEBUG: populating destination field - with leftover: %s" % (acl_line_remaining)
         match = re.search("^[ ]*object-group ([^ ]+) (.+)$", acl_line_remaining)
         destination_address = ""
         if match:
            og_name = match.group(1)
            acl_line_remaining = match.group(2)
            print "DEBUG: populating destination field based on og: %s" % (og_name)
            og = parent_fwconfig.get_objectgroup(og_name)
            # the destination_list in the policy will only consist of the address-set we're about to create
            destination_list.append(og_name)
            # set security zones security-zone untrust address-book address 10.156.250.230/32 10.156.250.230/32
            # set security zones security-zone untrust address-book address 10.156.250.15/32 10.156.250.15/32
            # set security zones security-zone untrust address-book address-set NG-OUTSIDE-DMZ_NETWORK address 10.156.250.0/24
            # set security zones security-zone untrust address-book address-set NG-OUTSIDE-DMZ_SWITCHES address 10.156.250.231/32
            for destination in og.item_list:
               destination_address = parent_fwconfig.convert_address_to_junos(destination.right_hand_side)
               #print "DEBUG: adding destination.right_hand_side = %s" % (destination.right_hand_side)
               address_entry_statement = "set security zones security-zone %s address-book address %s %s"             % (policy_to, destination_address, destination_address)
               address_set_statement   = "set security zones security-zone %s address-book address-set %s address %s" % (policy_to, og_name,             destination_address)
               junos_address_entry_list.append(address_entry_statement)
               junos_address_set_list.append(address_set_statement)
               print address_entry_statement
               print address_set_statement
         else:
            print "DEBUG: convert_to_junos - no og in destination field found"
            match = re.search("^[ ]*host ([^ ]+) (.+)$", acl_line_remaining)
            if match:
               destination_field      = match.group(1)
               acl_line_remaining      = match.group(2)
               destination_address    = "%s%s" % (destination_field, "/32")
               print "DEBUG: populating destination field: %s" % (destination_address)
               destination_list.append(destination_address)
            else:
               match = re.search("^[ ]*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (.+)$", acl_line_remaining)
               if match:
                  destination_field = match.group(1)
                  acl_line_remaining = match.group(2)
                  destination_address = parent_fwconfig.convert_address_to_junos(destination_field)
                  print "DEBUG: populating destination field: %s" % (destination_address)
                  destination_list.append(destination_address)
               else:
                  print "DEBUG: ERROR didn't match destination field!!"
            address_entry_statement = "set security zones security-zone %s address-book address %s %s" % (policy_to, destination_address, destination_address)
            junos_address_entry_list.append(address_entry_statement)
            print address_entry_statement
         
         # populate application field
         print "DEBUG: populating application field - with leftover: %s" % (acl_line_remaining)
         match = re.search("^[ ]*object-group ([^ ]+)[ ]*$", acl_line_remaining)
         if match:
            og_name = match.group(1)
            acl_line_remaining = ""
            print "DEBUG: populating application field based on og: %s" % (og_name)
            og = parent_fwconfig.get_objectgroup(og_name)
            application_list_name = og_name
            for item in og.item_list:
               application = parent_fwconfig.convert_application_to_junos(item.right_hand_side)
               application_list.append(application)
         else:
            print "DEBUG: convert_to_junos - no og in application field found"
            match = re.search("^[ ]*eq ([^ ]+)[ ]*$", acl_line_remaining)
            if match:
               application_field = match.group(1)
               acl_line_remaining = ""
               print "DEBUG: populating application field: %s" % (application_field)
               application = parent_fwconfig.convert_application_to_junos(application_field)
               application_list.append(application_field)
               application_list_name = "port_%s" % (application_field)
            else:
               # if we didn't match the above, grab whatever's left of the line
               match = re.search("^[ ]*(.+)$", acl_line_remaining)
               if match:
                  application_field = match.group(1)
                  acl_line_remaining = ""
                  print "DEBUG: didn't understand application field: %s" % (application_field)
                  application = parent_fwconfig.convert_application_to_junos(application_field)
                  application_list.append(application_field)
                  application_list_name = "port_%s" % (application_field)
         # generate applications statements
         ### example applications
         # set applications application SG-DOMAIN_PORTS_TCP1 term 1 protocol tcp
         # set applications application SG-DOMAIN_PORTS_TCP1 term 1 destination-port 389
         # set applications application SG-DOMAIN_PORTS_TCP1 term 2 protocol tcp
         # set applications application SG-DOMAIN_PORTS_TCP1 term 2 destination-port domain
         junos_applications_statements_list = []
         term_index = 1
         for protocol in protocol_list:
            for app in application_list:
               applications_statement_1 = "set applications application %s term %d protocol %s"         % (application_list_name, term_index, protocol)
               applications_statement_2 = "set applications application %s term %d destination-port %s" % (application_list_name, term_index, app)
               junos_applications_statements_list.append(applications_statement_1)
               junos_applications_statements_list.append(applications_statement_2)
               print applications_statement_1
               print applications_statement_2
               term_index = term_index + 1
         # we just created a junos application set, reset the application list to it's name
         application_list = [application_list_name]
         
         # set policy_name
         # if either first the source_list or then the destination_list is length one, and is an object group,
         # set the policy_name to it, otherwise, set policy_name to something unique
         if   (len(source_list) == 1)      and re.search("[A-z]", source_list[0]):
            policy_name = source_list[0]
         elif (len(destination_list) == 1) and re.search("[A-z]", destination_list[0]):
            policy_name = destination_list[0]
         else:
            policy_name = "POLICY_%d" % (policy_number)
            print "DEBUG: creating policy_name, source & dest lists, and lengths: " ,
            print "DEBUG: %s" % (source_list[0]) ,
            print "DEBUG: %s" % (destination_list[0]) ,
            print "DEBUG: %d" % (len(source_list)) ,
            print "DEBUG: %d" % (len(destination_list))
        
         # at the end of it all, print out the policy:
         #print "DEBUG: source_list"
         for source       in source_list:
            print "set security policies %s policy %s match source-address %s" % (policy_from_to, policy_name, source)
         #print "DEBUG: destination_list"
         for destination  in destination_list:
            print "set security policies %s policy %s match destination-address %s" % (policy_from_to, policy_name, destination)
         #print "DEBUG: protocol_list"
         #for protocol     in protocol_list:
         #   print protocol
         #print "DEBUG: application_list"
         for application  in application_list:
            print "set security policies %s policy %s match application %s" % (policy_from_to, policy_name, application)
         print "set security policies %s policy %s then permit"            % (policy_from_to, policy_name)
         print "set security policies %s policy %s then log session-init"  % (policy_from_to, policy_name)
         print "set security policies %s policy %s then log session-close" % (policy_from_to, policy_name)
         
         ### example addresses
         # set security zones security-zone trust address-book address 10.155.50.0/24 10.155.50.0/24
         # set security zones security-zone trust address-book address 10.138.8.190/32 10.138.8.190/32
         ### example address sets
         # set security zones security-zone trust address-book address-set NG-INSIDE-TSM_BACKUP_SERVERS address 10.155.202.1/32
         # set security zones security-zone trust address-book address-set NG-INSIDE-TSM_BACKUP_SERVERS address 192.168.70.178/32
         ### example security policy
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT match source-address NG-INSIDE-OMS_SUPPORT
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT match source-address NG-INSIDE-OMS_ADMINS
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT match destination-address NG-OUTSIDE-OMS_SERVERS
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT match destination-address NG-OUTSIDE-OMS_DB_SERVER
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT match application SG-OMS_SUPPORT_PORTS
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT then permit
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT then log session-init
         # set security policies from-zone trust to-zone untrust policy INSIDE-OMS-SUPPORT then log session-close
         ### example applications
         # set applications application SG-DOMAIN_PORTS_TCP1 term 1 protocol tcp
         # set applications application SG-DOMAIN_PORTS_TCP1 term 1 destination-port 389
         # set applications application SG-DOMAIN_PORTS_TCP1 term 2 protocol tcp
         # set applications application SG-DOMAIN_PORTS_TCP1 term 2 destination-port domain

class StaticNAT:
   def __init__(self, static_nat):
      self.static_nat = static_nat
   def print_me(self):
      print "StaticNAT.print_me() static nat: " + self.static_nat


class Name:
   def __init__(self, address, label):
      self.address = address
      self.label   = label
   def __str__(self):
      return self.label + " = " + self.address
   def contains_IP(self, IP):
      # convert 192.168.83.19 -> 192\.168\.83\.19
      IP_pattern = re.sub("\.", r"\.", IP)
      IP_pattern = r"\b" + IP_pattern + r"\b"
      #vprint("OGI.contains_IP() checking item: " + item)
      match = re.search(IP_pattern, self.address)
      if match:
         #vprint("OGI.contains_IP() true")
         return True
      else:
         #vprint("OGI.contains_IP() false")
         return False
   def print_me(self):
      print "Name.print_me() name: " + self.label + " = " + address


class Route:
   def __init__(self, route):
      self.route = route
   def print_me(self):
      print "Route.print_me() route: " + self.route

def main():
   
   """ an attempt at full instrumentation below """
   
   fw_conf_for_testing = FirewallConfig("fw_conf_for_testing")
   if fw_conf_for_testing is None:
      print "Error: empty config or invalid/unrecognized firewall config file"
      exit()
   
   example_og_name = "test_object_group"
   
   print "print out of firewall's data structure:"
   fw_conf_for_testing.print_me()
   print ""

   first_og =  fw_conf_for_testing.og_dict[ example_og_name ]
   
   print "take the following example object group, searched for using this name: >" + example_og_name + "<:"
   print ""
   print "normal print_me:"
   first_og.print_me()
   print ""
   print "config style print:"
   first_og.print_config_format()
   print ""
   
   print "In order to give the new IP 192.168.83.22 the same access as 192.168.83.19, these commands would be required:"
   for command in first_og.get_conf_clone_IP("192.168.83.19", "192.168.83.22"):
      print command
   print ""
   
   print "testing certain functionality of OG class:"
   example_ip1 = "198.170.67.13" ; print "Is the IP " + example_ip1 + " in it? ", ; print first_og.contains_IP(example_ip1)
   example_ip2 = "198.170.67.133"; print "Is the IP " + example_ip2 + " in it? ", ; print first_og.contains_IP(example_ip2)
   example_ip3 = "192.168.71.37" ; print "Is the IP " + example_ip3 + " in it? ", ; print first_og.contains_IP(example_ip3)
   example_ip4 = "192.168.83.19" ; print "Is the IP " + example_ip4 + " in it? ", ; print first_og.contains_IP(example_ip4)
   
   
   
   
   
   print "testing class FirewallConfig init()"

   print "reading in a small firewall conf"
   fw_conf_for_testing = FirewallConfig("fw_conf_for_testing2")
   
   print "orig version fw_conf_for_testing.print_me()"
   fw_conf_for_testing.print_me()
   print ""
   
   og_name = "test_object_group_2"
   print "getting og group " + og_name + " using fw_conf_for_testing.get_objectgroup(og_name)"
   fw_conf_for_testing.get_objectgroup(og_name)
   
   print "creating a new object group, from scratch"
   # create arg list which we'll send to the OG constructor
   name, type, tcp_udp_option, description = "NG-TEST_CREATE_GROUP", "network", "", "this would be a full description"
   
   # create og item list
   cur_og_item_list = [ ]
   new_item = ObjectGroupItem(" network-object host 5.5.5.5")
   cur_og_item_list.append(new_item)
   new_item = ObjectGroupItem(" network-object 20.0.0.0 255.0.0.0")
   cur_og_item_list.append(new_item)
   
   # send collected item list to the OG constructor, to create a new object group
   og = ObjectGroup(name, type, tcp_udp_option, description, cur_og_item_list)
   print "newly created object group:"
   print og
   print ""
   
   # add to fwconfig
   print "adding this new object group to fwconfig"
   print "fw_conf_for_testing.add_objectgroup(og)"
   fw_conf_for_testing.add_objectgroup(og)
   
   print "fw_conf_for_testing.print_me(), after addition of new og"
   fw_conf_for_testing.print_me()
   print ""
   
   
   # class ObjectGroup
   print "testing class ObjectGroup"
   
   print "og.print_me()"
   og.print_me()
   print ""
   
   print "og.print_config_format()"
   og.print_config_format()
   print ""
   
   new_IP = "2.2.2.2"
   print "creating new item to play with, using host " + new_IP
   item = ObjectGroupItem(" network-object host " + new_IP)
   print "newly created item:"
   print item
   print ""
   
   print "og.add_item(item) running"
   og.add_item(item)
   print "current state of og:"
   print og
   print ""
   
   print "og.remove_item(item), removing the following item:"
   print item
   og.remove_item(item)
   print "after og.remove_item()"
   print "current state of og:"
   print og
   print ""
   
   find_IP = "5.5.5.5"
   
   print "og.contains_IP(IP), using this IP to look for: " + find_IP
   print og.contains_IP(find_IP)
   print ""
   
   print "og.get_item_with_IP(IP), using following IP to look for: " + find_IP
   item = og.get_item_with_IP(find_IP)
   print "found item:"
   print item
   print ""
   
   print "current state of og:"
   print og
   print ""
   
   old_IP = "5.5.5.5"
   new_IP = "6.6.6.6"
   
   print "testing og.clone_IP(old_IP, new_IP), using old_IP: " + old_IP + " new_IP: " + new_IP
   og.clone_IP(old_IP, new_IP)
   print "current state of og:"
   print og
   print ""
   
   old_IP = "6.6.6.6"
   new_IP = "10.10.10.10"
   
   print "og.replace_IP(old_IP, new_IP), using old_IP: " + old_IP + " new_IP: " + new_IP
   og.replace_IP(old_IP, new_IP)
   print "current state of og:"
   print og
   print ""
   
   mode = "oneshot"
   print "og.get_conf_replace_IP(mode, old_IP, new_IP) " + old_IP + " new_IP: " + new_IP
   print "these are the commands for replacement: " + "\n".join(og.get_conf_replace_IP(mode, old_IP, new_IP))
   print ""
   
   print "og.get_conf_clone_IP(old_IP, new_IP) " + old_IP + " new_IP: " + new_IP
   print "these are the commands for cloning: " + "\n".join(og.get_conf_clone_IP(old_IP, new_IP))
   print ""
   
   
   # class ObjectGroupItem
   print "testing class ObjectGroupItem"
   IP = "9.9.9.9"
   ogi = ObjectGroupItem(" network-object host " + IP)
   print ""

   print "testing ogi.print_config_format()"
   ogi.print_config_format()
   print ""
   
   print "testing ogi.contains_IP(IP): does ogi contain this IP: " + IP + "?"
   print ogi.contains_IP(IP)
   print ""
   
   old_IP = "9.9.9.9"
   new_IP = "10.10.10.10"
   print "current state of ogi:"
   print ogi
   print ""
   
   print "testing ogi.replace_IP(old_IP, new_IP), using old_IP: " + old_IP + " and new_IP: " + new_IP
   ogi.replace_IP(old_IP, new_IP)
   print "current state of ogi:"
   print ogi
   print ""
   
   print "testing ogi.get_IP()"
   print ogi.get_IP()
   print ""
   
   print "testing print ogi, using ogi.__str__()"
   print ogi
   print ""
   
   # class AccessList
   print "testing class AccessList"
   keys = acl_dict.keys()
   acl = acl_dict[keys[0]]
   print "acl before:"
   acl.print_me()
   test_ace = "access-list acl-out extended permit icmp object-group ng-inside-admin_network object-group ng-multi-network_device_nets echo"
   print "testing acl.add_acl_line()"
   acl.add_acl_line(test_ace)
   print "acl.print_me()"
   acl.print_me()
   print ""
   
   # class StaticNAT
   print "testing class StaticNAT"
   print "static.print_me()"
   static.print_me()
   print ""
   
   # class StaticNAT
   print "testing class StaticNAT"
   print "static.print_me()"
   static.print_me()
   print ""
   
   # class Route
   print "testing class Route"
   print "route.print_me()"
   route.print_me()


if __name__ == "__main__":
   main()


